package com.zwq.zwqjavanotes.utils;

import com.sun.org.apache.bcel.internal.generic.PUSH;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.StringJoiner;

/**
 * @ClassName InvokeRestFulUtil
 * @Description TODO
 * @Author @gnplum O_o
 * @Date 2025/5/15 16:13
 * @Version 1.0
 */
public class InvokeRestFulUtil {
    /*=======================================1、Spring RestTemplate（同步，已过时但兼容旧项目）=====================================*/
    private static final RestTemplate restTemplate = new RestTemplate();
    private static final String BASE_URL = "http://localhost:6666/api";

    /**
     * @return void
     * @Author gnplum
     * @Description GET 调用 Spring RestTemplate（同步，已过时但兼容旧项目）
     * @Date 16:54 2025/5/15
     **/
    public static void invokeGETByRestTemplate() {

        //GET无参
        String result = restTemplate.getForObject(BASE_URL, String.class);
        System.out.println("GET 无参结果：" + result);

        //GET 有参（路径参数）
        String url = BASE_URL + "/123"; // 路径参数 userId=123
        result = restTemplate.getForObject(url, String.class);
        System.out.println("GET 路径参数结果：" + result);

        //GET 有参（请求参数）
        url = BASE_URL + "/search?username=张三"; // 请求参数 username=张三
        result = restTemplate.getForObject(url, String.class);
        System.out.println("GET 请求参数结果：" + result);
    }

    /**
     * @return void
     * @Author gnplum
     * @Description POST 调用 Spring RestTemplate
     * @Date 16:56 2025/5/15
     **/
    public static void invokePOSTByRestTemplate() {
        //POST 无参
        String result = restTemplate.postForObject(BASE_URL + "/action", null, String.class);
        System.out.println("POST 无参结果：" + result);

        //POST 有参（表单参数）
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("name", "李四");
        formData.add("age", "25");
        result = restTemplate.postForObject(BASE_URL + "/form", formData, String.class);
        System.out.println("POST 表单参数结果：" + result);

        //POST 有参（JSON 参数）
        String jsonBody = "{\"name\":\"王五\",\"age\":30}";
        result = restTemplate.postForObject(BASE_URL + "/json", jsonBody, String.class);
        System.out.println("POST JSON 参数结果：" + result);
    }

    /*=======================================2、Spring WebClient（异步）=====================================*/
    private static final WebClient webClient = WebClient.create("http://localhost:6666/api");

    /**
     * @return void
     * @Author gnplum
     * @Description //get 请求调用 Spring WebClient（异步）
     * @Date 17:03 2025/5/15
     **/
    public static void invokeGETByWebClient() {

        // GET 无参
        webClient.get()
                .uri("")
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(result -> System.out.println("GET 无参结果：" + result));
        //GET 有参（路径参数）
        webClient.get()
                .uri("/{userId}", 123) // 路径参数 userId=123
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(result -> System.out.println("GET 路径参数结果：" + result));

        //GET 有参（请求参数）
        webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/search")
                        .queryParam("username", "张三") // 请求参数 username=张三
                        .build())
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(result -> System.out.println("GET 请求参数结果：" + result));
    }

    /**
     * @return void
     * @Author gnplum
     * @Description //POST 请求调用 Spring WebClient（异步）
     * @Date 17:04 2025/5/15
     **/
    public static void invokePOSTByWebClient() {
        //POST 无参
        webClient.post()
                .uri("/action")
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(result -> System.out.println("POST 无参结果：" + result));
        //POST 有参（表单参数）
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("name", "李四");
        formData.add("age", "25");
        webClient.post()
                .uri("/form")
                .header("Content-Type", "application/x-www-form-urlencoded")
                .bodyValue(formData)
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(result -> System.out.println("POST 表单参数结果：" + result));
        //POST 有参（JSON 参数）
        String jsonBody = "{\"name\":\"王五\",\"age\":30}";
        webClient.post()
                .uri("/json")
                .header("Content-Type", "application/json")
                .bodyValue(jsonBody)
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(result -> System.out.println("POST JSON 参数结果：" + result));
    }

    /*=======================================3、OkHttp（同步）=====================================*/
    private static final OkHttpClient client = new OkHttpClient();
    /**
     * @Author gnplum
     * @Description //GET 请求调用 OkHttp（同步）
     * @Date 17:08 2025/5/15
    * @return void
    **/
    public static void invokeGETByOkHttp() {
        //GET 无参
        Request request = new Request.Builder()
                .url("http://localhost:6666/api")
                .build();
        try (Response response = client.newCall(request).execute()) {
            System.out.println("GET 无参结果：" + response.body().string());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //GET 有参（路径参数+请求参数）
        String url = "http://localhost:6666/api/123?username=张三"; // 路径参数+请求参数
        Request request1 = new Request.Builder()
                .url(url)
                .build();
        try (Response response = client.newCall(request1).execute()) {
            System.out.println("GET 有参结果：" + response.body().string());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * @Author gnplum
     * @Description //POST 请求调用 OkHttp（同步）
     * @Date 15:06 2025/5/16
    * @return void
    **/
    public static void invokePOSTByOkHttp(){
        //POST 无参
        Request request = new Request.Builder()
                .url("http://localhost:6666/api/action")
                .post(RequestBody.create(null, new byte[0])) // 空请求体
                .build();
        try (Response response = client.newCall(request).execute()) {
            System.out.println("POST 无参结果：" + response.body().string());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //POST 有参（表单参数）
        okhttp3.RequestBody formBody = new okhttp3.FormBody.Builder()
                .add("name", "李四")
                .add("age", "25")
                .build();
        Request request1 = new Request.Builder()
                .url("http://localhost:6666/api/form")
                .post(formBody)
                .build();
        try (Response response = client.newCall(request1).execute()) {
            System.out.println("POST 表单参数结果：" + response.body().string());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //POST 有参（JSON 参数）
        okhttp3.RequestBody jsonBody = okhttp3.RequestBody.create(
                "{\"name\":\"王五\",\"age\":30}",
                okhttp3.MediaType.get("application/json")
        );
        Request request2 = new Request.Builder()
                .url("http://localhost:6666/api/json")
                .post(jsonBody)
                .build();
        try (Response response = client.newCall(request2).execute()) {
            System.out.println("POST JSON 参数结果：" + response.body().string());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

 /*=======================================4、OpenFeign（声明式调用，微服务友好）=====================================*/
    //### OpenFeign（声明式调用，微服务友好）
    //需添加依赖（ org.springframework.cloud:spring-cloud-starter-openfeign:2.2.9.RELEASE ，需配合 Spring Cloud）。

    /*
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "user-service", url = "http://localhost:8080/api/users")
public interface UserFeignClient {

    // GET 无参
    @GetMapping
    String getNoParam();

    // GET 有参（路径参数）
    @GetMapping("/{userId}")
    String getPathParam(@PathVariable Long userId);

    // GET 有参（请求参数）
    @GetMapping("/search")
    String getRequestParam(@RequestParam String username);

    // POST 无参
    @PostMapping("/action")
    String postNoParam();

    // POST 有参（表单参数）
    @PostMapping(value = "/form", consumes = "application/x-www-form-urlencoded")
    String postFormParam(@RequestParam String name, @RequestParam Integer age);

    // POST 有参（JSON 参数）
    @PostMapping(value = "/json", consumes = "application/json")
    String postJsonParam(@RequestBody String userJson);
}
*/


/*=================5、HttpURLConnection实现通用POST请求，支持无参、表单、JSON参数，支持自定义Header。==================*/
    /**
     * 通用 POST 请求方法（兼容无参、表单、JSON，支持自定义 Header）
     * @param url 目标接口 URL
     * @param paramType 参数类型（无参、表单、JSON）
     * @param params 参数内容（表单为 Map<String, String>，JSON 为 String，无参为 null）
     * @param headers 自定义请求头（键值对，如 "Authorization" -> "Bearer token"）
     * @return 响应内容（字符串）
     * @description：利用HttpURLConnection实现通用POST请求，支持无参、表单、JSON参数，支持自定义Header。
     * @author：gnplum
     */
    public static String post(
            String url,
            ParamType paramType,
            Object params,
            Map<String, String> headers
    ) throws IOException {
        HttpURLConnection connection = null;
        try {
            // 1. 初始化连接
            connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(5000); // 连接超时 5 秒
            connection.setReadTimeout(5000);    // 读取超时 5 秒

            // 2. 设置自定义 Header（如 Authorization、User-Agent 等）
            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }

            // 3. 根据参数类型设置 Content-Type 和请求体
            switch (paramType) {
                case FORM:
                    // 表单参数：application/x-www-form-urlencoded
                    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                    String formData = mapToFormString((Map<String, String>) params);
                    writeRequestBody(connection, formData);
                    break;
                case JSON:
                    // JSON 参数：application/json
                    connection.setRequestProperty("Content-Type", "application/json");
                    writeRequestBody(connection, (String) params);
                    break;
                case NONE:
                    // 无参：无需请求体（Content-Length 设为 0）
                    connection.setRequestProperty("Content-Length", "0");
                    break;
                default:
                    throw new IllegalArgumentException("不支持的参数类型: " + paramType);
            }

            // 4. 读取响应（Java 8 兼容方式）
            int responseCode = connection.getResponseCode();
            InputStream inputStream = (responseCode == HttpURLConnection.HTTP_OK)
                    ? connection.getInputStream()
                    : connection.getErrorStream();
            byte[] responseBytes = readAllBytesJava8(inputStream);
            return new String(responseBytes, StandardCharsets.UTF_8);

        } finally {
            if (connection != null) {
                connection.disconnect(); // 关闭连接
            }
        }
    }

    // 辅助方法：Map 转表单字符串（key1=value1&key2=value2）
    private static String mapToFormString(Map<String, String> formMap) {
        if (formMap == null || formMap.isEmpty()) {
            return "";
        }
        StringJoiner joiner = new StringJoiner("&");
        for (Map.Entry<String, String> entry : formMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() == null ? "" : entry.getValue();
            joiner.add(key + "=" + value);
        }
        return joiner.toString();
    }

    // 辅助方法：写入请求体（Java 8 兼容）
    private static void writeRequestBody(HttpURLConnection connection, String body) throws IOException {
        if (body == null || body.isEmpty()) {
            return;
        }
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
        connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
        connection.setDoOutput(true); // 启用输出流
        try (OutputStream os = connection.getOutputStream()) {
            os.write(bytes);
            os.flush();
        }
    }

    // 辅助方法：读取输入流所有字节（Java 8 兼容）
    private static byte[] readAllBytesJava8(InputStream inputStream) throws IOException {
        if (inputStream == null) {
            return new byte[0];
        }
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] data = new byte[1024]; // 缓冲区大小（可调整）
        int bytesRead;
        while ((bytesRead = inputStream.read(data)) != -1) {
            buffer.write(data, 0, bytesRead);
        }
        return buffer.toByteArray();
    }

    // 参数类型枚举
    public enum ParamType {
        NONE,   // 无参
        FORM,   // 表单参数（application/x-www-form-urlencoded）
        JSON    // JSON 参数（application/json）
    }
}
